﻿using System;
using System.Windows;
using System.Windows.Controls;

namespace Gmantis.Controls.Chart
{
    public enum ChartPanelAction
    {
        None,
        MouseMove,
        LeftMouseButtonDrag,
        RightMouseButtonDrag
    }

    public enum ChartPanelAttach
    {
        None,
        DataX,
        DataY,
        DataXY
    }

    public class ChartPanelObject : ContentControl
    {
        // Fields
        private DragHelper _dragHelper;
        private ChartPanel _panel;
        public static readonly DependencyProperty ActionProperty = DependencyProperty.Register("Action", typeof(ChartPanelAction), typeof(ChartPanelObject), new PropertyMetadata(ChartPanelAction.None, new PropertyChangedCallback(ChartPanelObject.OnActionChanged)));
        public static readonly DependencyProperty AttachProperty = DependencyProperty.Register("Attach", typeof(ChartPanelAttach), typeof(ChartPanelObject), new PropertyMetadata(ChartPanelAttach.None));
        public static readonly DependencyProperty AxisXProperty = DependencyProperty.Register("AxisX", typeof(string), typeof(ChartPanelObject), new PropertyMetadata("", new PropertyChangedCallback(ChartPanelObject.OnAxisXChanged)));
        public static readonly DependencyProperty AxisYProperty = DependencyProperty.Register("AxisY", typeof(string), typeof(ChartPanelObject), new PropertyMetadata("", new PropertyChangedCallback(ChartPanelObject.OnAxisYChanged)));
        public static readonly DependencyProperty DataPointProperty = DependencyProperty.Register("DataPoint", typeof(Point), typeof(ChartPanelObject), new PropertyMetadata(EmptyPoint, new PropertyChangedCallback(ChartPanelObject.OnDataPointChanged)));
        private static Point EmptyPoint = new Point(double.NaN, double.NaN);
        private bool notify = true;
        public static readonly DependencyProperty UseAxisLimitsProperty = DependencyProperty.Register("UseAxisLimits", typeof(bool), typeof(ChartPanelObject), new PropertyMetadata(true));

        // Events
        public event EventHandler DataPointChanged;

        // Methods
        private Point AdjustPoint(Point pt)
        {
            if ((this.Panel != null) && (this.Panel.Chart != null))
            {
                double actualMin;
                double actualMax;
                double num4;
                double num5;
                ChartView view = this.Panel.Chart.View;
                if (view == null)
                {
                    return pt;
                }
                Axis axisX = null;
                Axis axisY = null;
                if (!string.IsNullOrEmpty(this.AxisX))
                {
                    axisX = view.Axes[this.AxisX];
                }
                if (axisX == null)
                {
                    axisX = view.AxisX;
                }
                if (!string.IsNullOrEmpty(this.AxisY))
                {
                    axisY = view.Axes[this.AxisY];
                }
                if (axisY == null)
                {
                    axisY = view.AxisY;
                }
                if (axisX.Scale < 1.0)
                {
                    double num3 = (axisX.ActualMax - axisX.ActualMin) * axisX.Scale;
                    actualMin = axisX.ActualMin + (axisX.Value * ((axisX.ActualMax - axisX.ActualMin) - num3));
                    actualMax = actualMin + num3;
                }
                else
                {
                    actualMin = axisX.ActualMin;
                    actualMax = axisX.ActualMax;
                }
                if (axisY.Scale < 1.0)
                {
                    double num6 = (axisY.ActualMax - axisY.ActualMin) * axisY.Scale;
                    num4 = axisY.ActualMin + (axisY.Value * ((axisY.ActualMax - axisY.ActualMin) - num6));
                    num5 = num4 + num6;
                }
                else
                {
                    num4 = axisY.ActualMin;
                    num5 = axisY.ActualMax;
                }
                if (!double.IsNaN(pt.X))
                {
                    if (pt.X < actualMin)
                    {
                        pt.X = actualMin;
                    }
                    else if (pt.X > actualMax)
                    {
                        pt.X = actualMax;
                    }
                }
                if (double.IsNaN(pt.Y))
                {
                    return pt;
                }
                if (pt.Y < num4)
                {
                    pt.Y = num4;
                    return pt;
                }
                if (pt.Y > num5)
                {
                    pt.Y = num5;
                }
            }
            return pt;
        }

        private static void OnActionChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            ChartPanelObject obj2 = (ChartPanelObject)obj;
            if (obj2.Panel != null)
            {
                obj2.Panel.DetachEvents(obj2, (ChartPanelAction)args.OldValue);
                obj2.Panel.AttachEvents(obj2, (ChartPanelAction)args.NewValue);
            }
        }

        private static void OnAxisXChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            ((ChartPanelObject)obj).InvalidateMeasure();
        }

        private static void OnAxisYChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            ((ChartPanelObject)obj).InvalidateMeasure();
        }

        protected virtual void OnDataPointChanged(DependencyPropertyChangedEventArgs args)
        {
            if (this.DataPointChanged != null)
            {
                this.DataPointChanged(this, EventArgs.Empty);
            }
            if (this.notify && (this._panel != null))
            {
                this._panel.InvalidateArrange();
            }
        }

        private static void OnDataPointChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            ((ChartPanelObject)obj).OnDataPointChanged(args);
        }

        internal void SetPoint(Point pt)
        {
            double x = this.DataPoint.X;
            if (!double.IsNaN(x))
            {
                x = pt.X;
            }
            double y = this.DataPoint.Y;
            if (!double.IsNaN(y))
            {
                y = pt.Y;
            }
            if (this.UseAxisLimits)
            {
                pt = this.AdjustPoint(new Point(x, y));
            }
            if (double.IsNaN(pt.X))
            {
                pt.X = this.DataPoint.X;
            }
            if (double.IsNaN(pt.Y))
            {
                pt.Y = this.DataPoint.Y;
            }
            this.notify = false;
            this.DataPoint = pt;
            this.notify = true;
        }

        // Properties
        public ChartPanelAction Action
        {
            get
            {
                return (ChartPanelAction)base.GetValue(ActionProperty);
            }
            set
            {
                base.SetValue(ActionProperty, value);
            }
        }

        public ChartPanelAttach Attach
        {
            get
            {
                return (ChartPanelAttach)base.GetValue(AttachProperty);
            }
            set
            {
                base.SetValue(AttachProperty, value);
            }
        }

        public string AxisX
        {
            get
            {
                return (string)base.GetValue(AxisXProperty);
            }
            set
            {
                base.SetValue(AxisXProperty, value);
            }
        }

        public string AxisY
        {
            get
            {
                return (string)base.GetValue(AxisYProperty);
            }
            set
            {
                base.SetValue(AxisYProperty, value);
            }
        }

        public Point DataPoint
        {
            get
            {
                return (Point)base.GetValue(DataPointProperty);
            }
            set
            {
                base.SetValue(DataPointProperty, value);
            }
        }

        internal DragHelper DragHelper
        {
            get
            {
                return this._dragHelper;
            }
            set
            {
                this._dragHelper = value;
            }
        }

        internal ChartPanel Panel
        {
            get
            {
                return this._panel;
            }
            set
            {
                if (this._panel != value)
                {
                    if (this._panel != null)
                    {
                        this._panel.DetachEvents(this, this.Action);
                    }
                    this._panel = value;
                    if (this._panel != null)
                    {
                        this._panel.AttachEvents(this, this.Action);
                    }
                }
            }
        }

        public bool UseAxisLimits
        {
            get
            {
                return (bool)base.GetValue(UseAxisLimitsProperty);
            }
            set
            {
                base.SetValue(UseAxisLimitsProperty, value);
            }
        }
    }
}
